/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ArchivoPaginas;

import java.io.IOException;
import java.io.RandomAccessFile;

/**
 *
 * @author UNSAAC30X
 */
public class GestorIOPagina {
    /**

     * Construir una nuevo gestor de página de I/O.

     */

    public GestorIOPagina() {

    }




    /**

     * Escribe una página en un archivo de salida

     * 

     * @param raf archivo de salida.

     * @param pagina la página a ser escrita.

     * @throws StorageManagerException thrown whenever there is an

     * output error.

     */

    public static void escribirPagina(RandomAccessFile raf, Pagina pagina) {




        try {

            // buscar el lugar correcto en el archivo

            long seek = pagina.getIdentificadorPagina().getNumero() * 4096;

            raf.seek(seek);

            byte[] bytes = new byte[4096];

            volcarNumero(pagina, bytes);

            volcarTuplas(pagina, bytes);

            raf.write(bytes);

        } catch (IOException ioe) {

            System.out.println("Exception mientras se escribe la página "

                    + pagina.getIdentificadorPagina()

                    + " a disco: " + ioe);

        }

    }




    /**

     * Leer una página del disco.

     * 

     * @param relacion la relación a la que la página pertenece.

     * @param pid Identificador de la página.

     * @param raf el archivo de la salida.

     * @return la página leida.

     */

    public static Pagina leerPagina(Relacion relacion, IdentificadorPagina pid, RandomAccessFile raf) {

        try {

            // seek to the appropriate place

            long seek = pid.getNumero() * 4096;

            raf.seek(seek);

            byte[] bytes = new byte[4096];

            int leerBytes = raf.read(bytes);

            if (leerBytes == -1) {

                // hemos llegado al final del archivo, 

                // así que tenemos que asignar una página

                raf.setLength(seek + 4096);

                return new Pagina(relacion, pid);

            }

            if (leerBytes != 4096) {

                System.out.println("Pagina: " + pid.toString()

                        + "no fue leido completamente.");

            }

            return extraerTuplas(relacion, pid, bytes);

        } catch (IOException ioe) {

            System.out.println("Exception mientras se lee la página "

                    + pid.toString()

                    + " de disco. " + ioe);

            return null;

        }

    }




    /**

     * Volcar al arreglo de bytes el número de tuplas en la página.

     *

     * @param pagina la página a ser escrita.

     * @param bytes un arreglo de salida de bytes.     

     */

    protected static void volcarNumero(Pagina pagina, byte[] bytes) {




        byte[] b = Convert.toByte(pagina.getNumeroDeTuplas());

        System.arraycopy(b, 0, bytes, 0, b.length);

    }




    /**

     * Volcar a arreglo de bytes una página de tuplas a disco.

     * 

     * @param pagina la página a ser escrito en el disco.

     * @param bytes el arreglo de bytes de salida para las tuplas.

     */

    protected static void volcarTuplas(Pagina pagina, byte[] bytes) {




        // crear un nuevo gestor IO de tuplas

        GestorIOTupla gestor = new GestorIOTupla(pagina.getRelacion(),pagina.getIdentificadorPagina().getNombreArchivo());

        // Un numero entero se utiliza para el numero de tuplas

        int desplazamiento = Convert.INT_SIZE;

        // iterate sobre todas las tuplas de la página, y localizarlo en el arreglo

        for (Tupla tupla : pagina) {

            desplazamiento = gestor.escribirTupla(tupla, bytes, desplazamiento);

        }

        rellenar(bytes, desplazamiento);

    }




    /**

     * Leer las tuplas del disco y los coloca en una página.

     * 

     * @param relacion la relacion a la que pertenece la página.

     * @param pid el identificador de la nueva página.

     * @param bytes el arreglo de bytes donde las tuplas se encuentran.

     * @return la pagina leida del disco.

     */

    protected static Pagina extraerTuplas(Relacion relacion, IdentificadorPagina pid,

            byte[] bytes) {




        // crear un gestor IO de tupla

        GestorIOTupla gestor = new GestorIOTupla(relacion,pid.getNombreArchivo());

        // iniciar la lectura de tuplas

        int numeroDeTuplas = extraerNumero(bytes);

        Pagina pagina = new Pagina(relacion, pid);

        // Un numero entero se utiliza para el numero de tuplas

        int desplazamiento = Convert.INT_SIZE;

        for (int i = 0; i < numeroDeTuplas; i++) {

            Par par = gestor.leerTupla(bytes, desplazamiento);

            Tupla tupla = (Tupla) par.primero;

            desplazamiento = ((Integer) par.segundo).intValue();

            pagina.adicionarTupla(tupla);

        }




        return pagina;

    }




    /**

     * Extraer numero de tuplas del arreglo de byte.

     *

     * @param bytes el arreglo de bytes.

     * @return el numero de tuplas.

     */

    public static int extraerNumero(byte[] bytes) {




        byte[] b = new byte[Convert.INT_SIZE];

        System.arraycopy(bytes, 0, b, 0, b.length);

        return Convert.toInt(b);

    }




    /**

     * Rellena una matriz de bytes con ceros para alcanzar 

     * el tamaño de página de disco.  

     * 

     * @param bytes el arreglo de bytes de entrada a ser rellenado.

     * @param inicio el inicio del desplazamiento en el arreglo de bytes.

     */

    protected static void rellenar(byte[] bytes, int inicio) {

        for (int i = inicio; i < bytes.length; i++) {

            bytes[i] = (byte) 0;

        }
    }
}
